2023-01-05

Setting up pipewire for an external DAC

A few weeks ago, I decided to treat myself to some more desk clutter: An external DAC and amplifier box! Until now I used the lackluster on-board audio on my workstation, so this is a welcome improvement.

Now unfortunately pipewire by default does not automatically adjust its sampling rate based on the rate of the audio source and the audio sink, however it can be easiely configured to do so.

First, you want to get the ID if the alsa card device.

$  cat /proc/asound/cards

 0 [HDMI           ]: HDA-Intel - HDA ATI HDMI
                      HDA ATI HDMI at 0xfeb64000 irq 44
 1 [Generic        ]: HDA-Intel - HD-Audio Generic
                      HD-Audio Generic at 0xfeb60000 irq 16
 2 [Camera         ]: USB-Audio - Web Camera
                      Web Camera Web Camera at usb-0000:00:16.2-1, high speed
 3 [K38            ]: USB-Audio - K38
                      KTMicro K38 at usb-0000:00:16.0-2, full speed
 4 [Pro            ]: USB-Audio - FiiO K5 Pro
                      GuangZhou FiiO Electronics Co.,Ltd FiiO K5 Pro at usb-0000:00:13.2-1, high spee

Check the descriptions of each device to find your DAC. In the output above I highlighted mine. The number at the left is the ID. Now we need to find out which rates it supports and which formats.

$  cat /proc/asound/card4/stream0

GuangZhou FiiO Electronics Co.,Ltd FiiO K5 Pro at usb-0000:00:13.2-1, high spee : USB Audio

Playback:
  Status: Running
    Interface = 1
    Altset = 1
    Packet Size = 144
    Momentary freq = 95988 Hz (0xb.ffa0)
    Feedback Format = 16.16
  Interface 1
    Altset 1
    Format: S32_LE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000
    Data packet interval: 125 us
    Bits: 32
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 1
    Implicit Feedback Mode: No
  Interface 1
    Altset 2
    Format: S16_LE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000
    Data packet interval: 125 us
    Bits: 16
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 2
    Implicit Feedback Mode: No
  Interface 1
    Altset 3
    Format: SPECIAL DSD_U32_BE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000
    Data packet interval: 125 us
    Bits: 32
    DSD raw: DOP=0, bitrev=0
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 3
    Implicit Feedback Mode: No

Again, I highlighted the relevant lines in the output. We can neatly see all formats the DAC understands and the rates it supports them at. Now we want to create a pipewire configuration file. Pipewire is a user service, not a system service, so the sane thing to do here is to create a config file in your home directory.

$  mkdir -p ~/.config/pipewire/pipewire.conf.d/
$  $EDITOR ~/.config/pipewire/pipewire.conf.d/80-sample-rate.conf

Luckily pipewire already sets a good format by default for me, so I'll only be configuring the rate.

context.properties = {
	default.clock.allowed-rates = [ 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000 ]
}

Pipewire allows you to set up to 16 rates it can switch between. I set these to all the rates my DAC supports. It's usually a good idea to always leave the default 44100 in there as well, so that there won't be any issues if the DAC is not connected and pipewire falls back to some other audio sink. As an example, my DAC can be turned off, in which case pipwire will output audio via HDMI to my monitor which then plays it over its speakers. As you can imagine, that audio sink does not support a very high rate. I switch between DAC with headphones and monitor speakers regularly, so both being supported first class is a must for me.

Now restart pipewire (and your session manager, which likely is wireplumber!) and it just automatically adjust the rate. You can use the pw-top TUI tool to view the current rate of sources and sinks.

Do not be alarmed if the displayed rate does not match the highest one you configured! Pipewire automatically choses the one that fits best to the audio source and the audio sink. Any sane music player will adjust its rate according to the bitrate of the currently playing song. Most of your recordings will not be high-quality enough to really push the limits of your DAC and pipewire does the smart thing here by not setting the rate to a needlessly high value. As such it's a good idea to put all rates your DAC supports into the array in the config file, even the ones you think are low.

My Dac has a LED shining behind the volume controls. Its blue for rates matching CD quality and below, yellow for everything above. It's kinda fun seeing it change based on what songs I play. A lot of my music library is ripped from discs, so unsurprisingly it stays blue a lot.

What's annoying is that when you test your setup and you hear small pops and cracklings, it's not immediately obvious whether that's from the configuration being bad or is part of the audio file. When I set this up initially, I tested my setup with In My Afterlife by Emma Ruth Rundle (Playing the flac file of course, not YouTube. That link is just here for illustration purposes.) and a little bump in the actual recording at 12 seconds in got me a bit annoyed, because I at first confused with pipewire acting up. Also 16 seconds in there is some background noise and in one part the microphone is mildy overloaded. The things you notice with better equipment is ... quite something. The rest of the songs on that brilliant album have a better recording quality luckily.

Oh, and another thing! If you use software that allows you to set the profile of the audio device, like pavucontrol, then just don't. Leave it on the Analag Stereo one. Yes, the IEC958 one looks more sophisticated, but you really don't want to use that one. Same with the Pro Audio one, unless you actually, really know what you are doing.

And finally, you probably want a way to adjust the volume of the DAC sink as well; Yes, that is unrelated to the hardware volume you control by turning the knob. At least I found mine to be considerably to loud, even at lowest gain, after less then a quarter turn of the volume know. Pipewire defaults to a a sink volume of 1.0; I set mine to 0.6. The most convenient way to adjust sink levels is via wireplumber, I find.

$  wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+
$  wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-

Articles from blogs I read (generated by openring)

whippet lab notebook: guile, heuristics, and heap growth

Greets all! Another brief note today. I have gotten Guile working with one of the Nofl-based collectors, specifically the one that scans all edges conservatively (heap-conservative-mmc / heap-conservative-parallel-mmc). Hurrah!It was a pleasant surprise h…

wingolog, May 22, 2025

Status update, May 2025

Hi! Today wlroots 0.19.0 has finally been released! Among the newly supported protocols, color-management-v1 lays the first stone of HDR support (backend and renderer bits are still being reviewed) and ext-image-copy-capture-v1 enhances the previous screen ca…

emersion, May 15, 2025

Summary of changes for April 2025

Hey everyone!This is the list of all the changes we've done to our projects during the month of April. 100r.co, updated water, ditch bag, woodstove installation, and added new photos and information on first-aid kit. Rabbit Waves, updated Triangular…

Hundred Rabbits, April 30, 2025